package com.gxa.admin.config;

import com.gxa.admin.constants.SecurityConstants;
import com.gxa.admin.exception.JwtAccessDeniedHandler;
import com.gxa.admin.exception.JwtAuthenticationEntryPoint;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
import static java.util.Collections.singletonList;
import static org.springframework.security.config.Customizer.withDefaults;

/**
 * Spring Security配置
 * 代替拦截器在filter层面拦截请求(controller之前,更节省资源)
 * 实现更细粒度的权限控制
 * 使用比传统随机盐密码更安全的加密算法(默认bCrypt)
 * @author IKE <hp1041735092@outlook.jp>
 * @date 21/3/2024
 */

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final StringRedisTemplate stringRedisTemplate;
    public SecurityConfig(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }


    /**
     * 密码加密工具
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * spring security 核心配置
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors(withDefaults())
                .csrf().disable()   //关闭csrf防御;如需开启,前端请求标签必须携带name="_csrf"字段
                .authorizeRequests()
                /**
                 * 放行指定的接口
                 * @see SecurityConstants
                 */
//                .antMatchers(SecurityConstants.SWAGGER_WHITELIST).permitAll()
//                .antMatchers(SecurityConstants.H2_CONSOLE).permitAll()
//                .antMatchers(HttpMethod.POST,SecurityConstants.SYSTEM_WHITELIST).permitAll()
                .antMatchers("/**").permitAll()

                //其他接口都需要认证
                .anyRequest().authenticated()
                .and()

                //添加自定义filter
                .addFilter(new JwtAuthorizationFilter(authenticationManager(),stringRedisTemplate))
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .exceptionHandling().authenticationEntryPoint(new JwtAuthenticationEntryPoint())
                .accessDeniedHandler(new JwtAccessDeniedHandler());

        // 防止H2 web 页面的Frame 被拦截
        http.headers().frameOptions().disable();
    }


    /**
     * 跨域配置
     */
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        org.springframework.web.cors.CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedOrigins(singletonList("*"));
        // configuration.setAllowedOriginPatterns(singletonList("*"));
        corsConfiguration.setAllowedHeaders(singletonList("*"));
        corsConfiguration.setAllowedMethods(Arrays.asList("GET","POST","DELETE","PUT","OPTIONS"));
        corsConfiguration.setExposedHeaders(singletonList(SecurityConstants.TOKEN_HEADER));
        corsConfiguration.setAllowCredentials(false);
        corsConfiguration.setMaxAge(3600L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",corsConfiguration);
        return source;
    }


}
